package com.hmdp.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hmdp.dto.Result;
import com.hmdp.entity.VoucherOrder;
import com.hmdp.mapper.VoucherMapper;
import com.hmdp.mapper.VoucherOrderMapper;
import com.hmdp.service.ISeckillVoucherService;
import com.hmdp.service.IVoucherOrderService;
import com.hmdp.utils.RedisIDWorker;
import com.hmdp.utils.UserHolder;
import org.springframework.aop.framework.AopContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.redis.connection.stream.*;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.PostConstruct;
import java.time.Duration;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author 虎哥
 * @since 2021-12-22
 */
@Service
public class VoucherOrderServiceImpl extends ServiceImpl<VoucherOrderMapper, VoucherOrder> implements IVoucherOrderService {
   //订单mapper
    @Autowired
    private VoucherOrderMapper voucherOrderMapper;
    //普通优惠卷
    @Autowired
    private VoucherMapper voucherMapper;
    //秒杀优惠卷
    @Autowired
    private ISeckillVoucherService seckillVoucherService;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    //创建线程池
 public static final ExecutorService SECKILL_ORDER_EXECUTOR = Executors.newSingleThreadExecutor();
   //初始化的时候自动建立
 @PostConstruct
 private void init(){
  SECKILL_ORDER_EXECUTOR.submit(new VoucherOrderHandler());
 }
    //建立代理-->用于调用事务create
    private IVoucherOrderService proxy;
    //创建redis的脚本
 private static final DefaultRedisScript<Long> SECKILL_SCRIPT;
 static {
  SECKILL_SCRIPT = new DefaultRedisScript<>();
  SECKILL_SCRIPT.setLocation(new ClassPathResource("seckillHandler.lua"));
  SECKILL_SCRIPT.setResultType(Long.class);
 }

 @Override
 public Result seckillVoucher(Long voucherId) {
  //1.调用redis-->去判断
  //1.1获取用户的id
  Long userId = UserHolder.getUser().getId();
  //1.2获取订单id
  RedisIDWorker redisIDWorker = new RedisIDWorker(stringRedisTemplate);
  long orderId = redisIDWorker.nextID("order");
  //1.3调用对应的redis的脚本
  Long result = stringRedisTemplate.execute(
          SECKILL_SCRIPT,
          Collections.emptyList(),
          voucherId.toString(), userId.toString(), String.valueOf(orderId)
  );
  //2.判断结果
  int r = result.intValue();
  if(r != 0){
   return Result.fail(r==1?"库存不足":"重复下单");
  }

  //4.返回对应的orderid
  return Result.ok(orderId);

 }
 @Transactional
 public void createOrder(VoucherOrder voucherOrder){
   //1.获取订单的相关信息
  Long userId = voucherOrder.getUserId();
  Long voucherId = voucherOrder.getVoucherId();
  Long orderId = voucherOrder.getId();
  //2.判断一人一单问题
  //todo 删除redis中的订单信息,并且返回错误信息
  Integer count = voucherOrderMapper.selectCount(new LambdaQueryWrapper<VoucherOrder>()
          .eq(VoucherOrder::getUserId,userId)
          .eq(VoucherOrder::getVoucherId,voucherId));
  if(count!=0){
    log.error("重复下单");
  }
  //3.判断库存不足的问题
  //todo 删除redis中的订单信息,并且返回错误信息
  boolean success = seckillVoucherService.update()
          .setSql("stock=stock-1")
          .eq("voucher_id", voucherOrder.getVoucherId())
          .gt("stock", 0)
          .update();
  if(!success){
   log.error("库存不足");
   return;
  }
  //4.保存订单
  save(voucherOrder);
 }
 //用于处理redis中的订单信息
 private class VoucherOrderHandler implements Runnable {

  @Override
  public void run() {
   while(true){
    try {
     //1.取数据
     List<MapRecord<String, Object, Object>> list = stringRedisTemplate.opsForStream().read(
             Consumer.from("g1", "s1"),
             StreamReadOptions.empty().count(1).block(Duration.ofSeconds(2)),
             StreamOffset.create("stream.orders", ReadOffset.lastConsumed())
     );
      //2.判断订单信息是不是空
     if(list==null||list.isEmpty()){
      continue;
     }
     //3.解析数据
     MapRecord<String, Object, Object> record = list.get(0);
     Map<Object, Object> value = record.getValue();
     VoucherOrder voucherOrder = BeanUtil.fillBeanWithMap(value, new VoucherOrder(), true);
     //4.保存
     createOrder(voucherOrder);
     //5.发送确认ack
     stringRedisTemplate.opsForStream().acknowledge("s1", "g1",
             record.getId());

    }catch (Exception e){
     log.error("处理订单异常");
     PendingListHandler();
    }
   }
  }
 }

 private void PendingListHandler() {
  while(true){
   try {
    //1.取数据
    List<MapRecord<String, Object, Object>> list = stringRedisTemplate.opsForStream().read(
            Consumer.from("g1", "s1"),
            StreamReadOptions.empty().count(1).block(Duration.ofSeconds(2)),
            StreamOffset.create("stream.orders", ReadOffset.from("0"))
    );
    //2.判断订单信息是不是空
    if(list==null||list.isEmpty()){
     break;
    }
    //3.解析数据
    MapRecord<String, Object, Object> record = list.get(0);
    Map<Object, Object> value = record.getValue();
    VoucherOrder voucherOrder = BeanUtil.fillBeanWithMap(value, new VoucherOrder(), true);
    //4.保存
    createOrder(voucherOrder);
    //5.发送确认ack
    stringRedisTemplate.opsForStream().acknowledge("s1", "g1",
            record.getId());


   }catch (Exception e){
    log.error("处理订单异常");
   }
  }
 }
 }

